<template>
  <div>
    <vxe-drawer
      v-model="show"
      :title="$t('common.title.permission', '配置权限')"
      :loading="loading"
      :width="600"
      mask-closable
      show-footer
      show-confirm-button
      show-cancel-button
      @confirm="handleConfirm"
      @cancel="handleCancel"
    >
      <template #default>
        <div>
          <div class="flex-x-between">
            <el-input
              v-model="keywords"
              clearable
              :placeholder="
                $t('menu.dev.menu.placeholder.search', '输入菜单名称关键字搜索')
              "
            >
              <template #prefix>
                <Search />
              </template>
            </el-input>
            <div class="flex-center ml-5">
              <el-button type="primary" plain @click="toggleTree" icon="Switch">
                {{
                  isExpanded
                    ? $t('common.action.collapse', '收起')
                    : $t('common.action.expand', '展开')
                }}
              </el-button>
            </div>
          </div>
        </div>
        <div class="permission-area">
          <el-tree
            ref="treeRef"
            highlight-current
            show-checkbox
            accordion
            node-key="code"
            :data="options"
            :props="defaultProps"
            :check-strictly="false"
            :filter-node-method="handleFilter"
          />
        </div>
      </template>
    </vxe-drawer>
  </div>
</template>

<script setup>
import { smartTranslate as $t, transPlaceholder as $p } from '@/lang';

defineOptions({
  name: 'RolePermission',
  inheritAttrs: false,
});

const props = defineProps({
  api: {
    type: Object,
    required: true,
    validator: (value) => {
      return typeof value.setPermission === 'function';
    },
  },
  options: {
    type: Object,
    default: () => ({}),
  },
});

/**
 * 定义可触发事件 update 此事件触发后
 * 会执行绑定到此事件上的父组件函数
 */
const emit = defineEmits(['reload']);

/**
 * 普通变量
 */
const defaultProps = {
  children: 'children',
  label: 'label',
};

/**
 * 响应式变量
 */
const show = ref(false);
const loading = ref(false);
const treeRef = ref();
const options = ref();
const currentRoleId = ref();
const isExpanded = ref(false);
const keywords = ref();

// 权限筛选
watch(keywords, (val) => {
  treeRef.value.filter(val);
});

/**
 * 暴露出去的方法
 */
defineExpose({
  show(role_id) {
    loading.value = true;
    currentRoleId.value = role_id;
    props.api
      .getMenuTreeOptions()
      .then(({ data }) => {
        options.value = data;
        props.api.getPermission({ role_id }).then(({ data }) => {
          const checkedMenuIds = data;
          // 必须采用不递归选中 setChecked(key/data, checked, deep)
          treeRef.value.setCheckedKeys([]);
          checkedMenuIds.forEach((code) =>
            treeRef.value.setChecked(code, true, true),
          );
        });
      })
      .finally(() => {
        show.value = true;
        loading.value = false;
      });
  },
});

/**
 * 自定义方法
 */

// 取消按钮
const handleCancel = () => {
  show.value = false;
};

const handleConfirm = () => {
  const fullyCheckedNodes = treeRef.value.getCheckedNodes(false, false);
  // const fullyCheckedKeys = new Set(fullyCheckedNodes.map((node) => node.id));
  // console.log('fullyCheckedKeys:', fullyCheckedKeys);
  const halfCheckedNodes = treeRef.value.getHalfCheckedNodes();
  // const halfCheckedKeys = new Set(halfCheckedNodes.map((node) => node.id));
  // console.log('halfCheckedKeys:', halfCheckedKeys);

  const finalIds = [];
  const processedParentIds = new Set(); // 记录已经处理过的父节点
  fullyCheckedNodes.forEach((node) => {
    // 如果节点有子节点，说明它是一个父节点
    if (node.children && node.children.length > 0) {
      // 此父节点的所有子节点都被选中了，所以它本身是全选状态
      finalIds.push(node.id); // 提取父节点的 id
      // 记录下来，以便后续跳过它的子节点
      processedParentIds.add(node.id);
    } else {
      // 如果菜单节点没有叶子节点还被选中，说明他没有方法节点
      if (node.id < 10000) {
        finalIds.push(node.id);
        processedParentIds.add(node.id);
      }
    }
  });

  halfCheckedNodes.forEach((parentNode) => {
    // 对于每个半选的父节点，我们需要找到它下面被选中的子节点
    // 我们可以再次利用 fullyCheckedNodes 数组，因为那里包含了所有被选中的叶子节点
    fullyCheckedNodes.forEach((checkedNode) => {
      if (
        parentNode.children &&
        parentNode.children.some((child) => child.id === checkedNode.id)
      ) {
        // 确保这个子节点所属的父节点没有被整体处理过
        if (!processedParentIds.has(parentNode.id)) {
          finalIds.push(checkedNode.id); // 只提取选中的子节点的 id
        }
      }
    });
  });
  // 如果有些被选中的节点，其父节点既不是全选也不是半选（例如根节点下的第一级节点）
  fullyCheckedNodes.forEach((node) => {
    // 如果一个节点没有子节点（是叶子节点），并且尚未被包含在结果中
    // 这通常意味着它的父节点未被选中
    const isLeaf = !node.children || node.children.length === 0;
    // 检查该节点或其父节点是否已被处理
    const parent = findParent(options.value, node.id); // 你需要一个辅助函数来找父节点
    if (
      isLeaf &&
      !processedParentIds.has(parent ? parent.id : null) &&
      !finalIds.includes(node.id)
    ) {
      finalIds.push(node.id);
    }
  });

  props.api
    .setPermission({
      role_id: currentRoleId.value,
      ids: finalIds,
    })
    .then(() => {
      ElMessage.success(
        $t('common.message.success.general', {
          action: $t('common.action.save'),
        }),
      );
      show.value = false;
      emit('reload');
    });
};

function findParent(treeData, nodeId) {
  for (const node of treeData) {
    if (node.children) {
      if (node.children.some((child) => child.id === nodeId)) {
        return node;
      }
      const parent = findParent(node.children, nodeId);
      if (parent) return parent;
    }
  }
  return null;
}

// 执行数据过滤
function handleFilter(value, data) {
  if (!value) return true;
  return data.label.includes(value);
}

// 展开/收缩 菜单权限树
function toggleTree() {
  isExpanded.value = !isExpanded.value;
  if (treeRef.value) {
    Object.values(treeRef.value.store.nodesMap).forEach((node) => {
      if (isExpanded.value) {
        node.expand();
      } else {
        node.collapse();
      }
    });
  }
}

onMounted(() => {
  if (treeRef.value) {
    Object.values(treeRef.value.store.nodesMap).forEach((node) => {
      if (isExpanded.value) {
        node.expand();
      } else {
        node.collapse();
      }
    });
  }
});
</script>

<style lang="scss" scoped>
.permission-area {
  border: 1px solid #efefef;
  height: 80vh;
  overflow: auto;
  margin-top: 10px;
}
</style>
